﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

public class CorridorFirstDungeonGenerator : SimpleRandomWalkDungeonGenerator
{
    private Vector2Int Lastdirection = new Vector2Int(0, 0);
    [SerializeField]
    private int corridorLength, corridorCount;
    [SerializeField]
    [Range(0.1f, 1)]
    private float roomPercent = 0.8f;

    public int allowNum;//最大连续房间数量
    public GameObject nextScene;
    private int repetitionsNum = 0;

    public GameObject Enemies;//所有敌人的父物体
    public GameObject Cells;//所有Cell的父物体

    public GameObject enemy1;
    [HideInInspector]
    public GameObject enemy2;
    [HideInInspector]
    public GameObject enemy3;
    [HideInInspector]
    public GameObject enemy4;

    public GameObject MapCreater;//作为下一关传送门的父物体

    public GameObject Cell;//每格上生成一个用于鼠标射线检测

    private HashSet<Vector2Int> canMovePos = new HashSet<Vector2Int>(); // 定义变量
    public EnemyAi EnemyAi;
    //可移动位置，用于A*寻路

    //private void Update()
    //{
    //    if(EnemyAi.canMovePos!=null)
    //    Debug.Log("可移动数量"+EnemyAi.canMovePos.Count);
    //}

    protected override void RunProceduralGeneration()
    {
        CorridorFirstGeneration();
    }

    private void CorridorFirstGeneration()
    {

        GameObject[] a = GameObject.FindGameObjectsWithTag("enemy");
        GameObject[] b = GameObject.FindGameObjectsWithTag("nextScene");
        GameObject[] c = GameObject.FindGameObjectsWithTag("Cell");
        GameObject[] taggedObjects = a.Concat(b).ToArray();
        taggedObjects = taggedObjects.Concat(c).ToArray();
        for (int i = 0; i < taggedObjects.Length; i++)
        {
            DestroyImmediate(taggedObjects[i]);
        }//用于调试时删除实例化的物体，记得删


        HashSet<Vector2Int> floorPositions = new HashSet<Vector2Int>();
        HashSet<Vector2Int> potentialRoomPositions = new HashSet<Vector2Int>();

        CreateCorridors(floorPositions, potentialRoomPositions);
        /*创建一系列的走廊，用于连接房间，并将廊道位置添加到floorPositions集合中，
         * 同时将廊道的末端添加到potentialRoomPositions集合中，以便以后可以从这些末端点添加其他房间。*/

        var result = CreateRooms(potentialRoomPositions);
        HashSet<Vector2Int> roomPositions = result.Item1;
        List<List<Vector2Int>> allOrdRoomPositions = result.Item2;


        List <Vector2Int> deadEnds = FindAllDeadEnds(floorPositions);

        CreateRoomsAtDeadEnd(deadEnds, roomPositions);

        floorPositions.UnionWith(roomPositions);//计算合并集

        tilemapVisualizer.PaintFloorTiles(floorPositions);

        WallGenerator.CreateWalls(floorPositions, tilemapVisualizer);

        foreach (var position in floorPositions)
        {
            Instantiate(Cell, new Vector3(position.x + 0.5f, position.y + 0.5f, 0), Quaternion.identity).transform.parent = Cells.transform;
        }
        foreach (var List in allOrdRoomPositions)
        {
            HashSet<Vector2Int> room = new HashSet<Vector2Int>(List);
            CreateEnemy(room);
        }//创建敌人

        canMovePos = floorPositions;
        EnemyAi.CanMovePos = canMovePos;
        Debug.Log("可移动" + canMovePos.Count + "格");


    }

    private void CreateRoomsAtDeadEnd(List<Vector2Int> deadEnds, HashSet<Vector2Int> roomFloors)
    {
        foreach (var position in deadEnds)
        {
            if(roomFloors.Contains(position) == false)
            {
                var room = RunRandomWalk(randomWalkParameters, position);
                roomFloors.UnionWith(room);
            }
        }
    }

    private List<Vector2Int> FindAllDeadEnds(HashSet<Vector2Int> floorPositions)
    {
        List<Vector2Int> deadEnds = new List<Vector2Int>();
        foreach (var position in floorPositions)
        {
            int neighboursCount = 0;
            foreach (var direction in Direction2D.cardinalDirectionsList)
            {
                if (floorPositions.Contains(position + direction))
                    neighboursCount++;
                
            }
            if (neighboursCount == 1)
                deadEnds.Add(position);
        }
        return deadEnds;
    }

    private Tuple<HashSet<Vector2Int>, List<List<Vector2Int>>> CreateRooms(HashSet<Vector2Int> potentialRoomPositions)
    {
        HashSet<Vector2Int> temporaryRoomPositions = new HashSet<Vector2Int>();
        List<List<Vector2Int>> allOrdRoomPositions = new List<List<Vector2Int>>();

        potentialRoomPositions.Remove(startPosition);
        HashSet<Vector2Int> roomPositions = new HashSet<Vector2Int>();
        List<Vector2Int> farRooms = new List<Vector2Int>();
        int roomToCreateCount = Mathf.RoundToInt(potentialRoomPositions.Count * roomPercent);
        int maxstep=0;


        List<Vector2Int> roomsToCreate = potentialRoomPositions.OrderBy(x => Guid.NewGuid()).Take(roomToCreateCount).ToList();
        //按照Guid.NewGuid()的值对potentialRoomPositions进行排序;
        //从排序后的potentialRoomPositions中取出roomToCreateCount个Vector2Int实例
        List<Vector2Int> remainingRoomsToCreate = potentialRoomPositions.Except(roomsToCreate).ToList();//未生成房间的走廊末端

        foreach (var position in remainingRoomsToCreate)
        {
            for (int i = position.x - (int)Math.Floor(corridorLength / 3.0); i <= position.x + (int)Math.Floor(corridorLength / 3.0); i++)
            {
                for (int j = position.y - (int)Math.Floor(corridorLength / 3.0); j <= position.y + (int)Math.Floor(corridorLength / 3.0); j++)
                {
                    roomPositions.Add(new Vector2Int(i, j));
                    //if (i == position.x - (int)Math.Floor(corridorLength / 2.0))
                    //{
                    //    Instantiate(nextScene, new Vector3(i, j, 0), Quaternion.identity);
                    //}
                    //if (j == position.y - (int)Math.Floor(corridorLength / 2.0))
                    //{
                    //    Instantiate(nextScene, new Vector3(i, j, 0), Quaternion.Euler(0, 0, 90));
                    //}
                }
            }
        }//为空走廊末端添加房间（暂用）
        roomsToCreate.Add(startPosition);//加入起点使其必为房间

        foreach (var room in roomsToCreate)
        {
            if (Math.Abs((room.x - startPosition.x) / corridorLength) + Math.Abs((room.y - startPosition.y) / corridorLength) >maxstep)
            {
                maxstep = Math.Abs((room.x - startPosition.x) / corridorLength) + Math.Abs((room.y - startPosition.y) / corridorLength);
            }
        }//找到最大距离，来自麦扣的rogue教程
        foreach (var roomPosition in roomsToCreate)
        {
            {
                if (Math.Abs((roomPosition.x - startPosition.x) / corridorLength) + Math.Abs((roomPosition.y - startPosition.y) / corridorLength) == maxstep || Math.Abs((roomPosition.x - startPosition.x) / corridorLength) + Math.Abs((roomPosition.y - startPosition.y) / corridorLength) == maxstep - 1)
                {
                    farRooms.Add(roomPosition);
                }
            }//找到最远房间和最远少一步房间。用于在其中找终点房间并放置下一关传送点。
            var roomFloor = RunRandomWalk(randomWalkParameters, roomPosition);

            var uniqueRoomPositions = new HashSet<Vector2Int>(roomFloor);
            uniqueRoomPositions.ExceptWith(temporaryRoomPositions); // 从当前房间的位置列表中移除已经出现过的位置
            allOrdRoomPositions.Add(roomFloor.ToList()); // 将当前位置添加到列表中
            temporaryRoomPositions.UnionWith(uniqueRoomPositions);//用于排除重复位置

            //可于此添加clear方法，清除超出预定大小的position，如不想让房间除走廊外相连可将预定大小设为（corridorLength/2)

            roomPositions.UnionWith(roomFloor);
        }//对 roomsToCreate 列表中的每一组房间位置，使用 RunRandomWalk() 函数随机步行，生成一个房间，然后将这个房间的位置加入到 roomPositions 集合中
        
        var endroom = farRooms[UnityEngine.Random.Range(0, farRooms.Count - 1)];
        Instantiate(nextScene, new Vector3(endroom.x+0.5f, endroom.y+0.5f, 0), Quaternion.identity).transform.parent = MapCreater.transform;
        return Tuple.Create(roomPositions, allOrdRoomPositions);
    }

    private void CreateEnemy(HashSet<Vector2Int> roomFloor)
    {
        int placeNum = roomFloor.Count;
        HashSet<Vector2Int> Pos = roomFloor;

        //// 获取所有敌人预制体
        //GameObject[] enemyPrefabs = Resources.LoadAll<GameObject>("Prefab/Enemies");

        // 获取敌人数量
        int enemyCount = 1/*enemyPrefabs.Length*/;

        

        // 计算最大数字和  int maxNumber = Mathf.Min(totalNumber, placeNum);

        // 随机生成敌人
        while (placeNum >= 0)
        {
            // 随机选择一个敌人预制体
            int randomIndex = 0;// UnityEngine.Random.Range(0, enemyCount);有两种怪了再改回来
            GameObject enemyPrefab = enemy1/*enemyPrefabs[randomIndex]*/;

            // 获取敌人脚本
            EnemyScript enemyScript = enemyPrefab.GetComponent<EnemyScript>();

            // 判断敌人数字是否超过剩余地格数量
            int enemyNumber = enemyScript.placeNumber;
            //if (enemyNumber > placeNum)
            //{
            //    continue;
            //}

            // 随机选择一个地格位置
            Vector2Int randomTile = Pos.ElementAt(UnityEngine.Random.Range(0, roomFloor.Count));

            // 在该位置生成敌人并设置父物体
            Instantiate(enemyPrefab, new Vector3(randomTile.x+0.5f, randomTile.y+0.5f, 0), Quaternion.identity).transform.parent = Enemies.transform;

            // 将该位置从可用地格列表中移除
            Pos.Remove(randomTile);

            // 更新最大数字和
            placeNum -= enemyNumber;

        }
    }//为单个房间生成敌人

    private void CreateCorridors(HashSet<Vector2Int> floorPositions, HashSet<Vector2Int> potentialRoomPositions)
    {
        var currentPosition = startPosition;
        potentialRoomPositions.Add(currentPosition);

        for (int i = 0; i < corridorCount; i++)
        {
            Tuple<List<Vector2Int>, Vector2Int,int> myTuple = ProceduralGenerationAlgorithms.RandomWalkCorridor(currentPosition, corridorLength,Lastdirection,allowNum,repetitionsNum);
            var corridor= myTuple.Item1;
            Lastdirection = myTuple.Item2;
            repetitionsNum=myTuple.Item3;
            Debug.Log("走廊随机中"+Lastdirection);
            currentPosition = corridor[corridor.Count - 1];//corridor[corridor.Count - 1]是每条走廊终点
            potentialRoomPositions.Add(currentPosition);
            floorPositions.UnionWith(corridor);
        }
        
        foreach(Vector2Int position in potentialRoomPositions)
        {
            foreach(Vector2Int direction in Direction2D.cardinalDirectionsList)
            {
                if(potentialRoomPositions.Contains(position+direction* (corridorLength)))
                {
                    for (int i = 0; i < corridorLength; i++)
                    {
                        floorPositions.Add(position + direction*(i+1));
                    }//连接相邻走廊拐角

                    //可于此检测所需的房间开口类型并放入列表，用于特殊手绘房间的生成
                    //若想检测四周房间的类型，可在检测完单个房间并储存后，再次遍历并检测（注意四个方块型）
                }
            }
        }

    }
}
